package com.gitee.wsl.mathematics.geometry.d2.circle

import com.gitee.wsl.mathematics.coordinate.d2.Coordinate2
import com.gitee.wsl.mathematics.geometry.api.EllipseShape
import com.gitee.wsl.mathematics.geometry.d2.CloseShape2d
import com.gitee.wsl.mathematics.geometry.d2.PointShape2d
import com.gitee.wsl.mathematics.geometry.d2.base.SizeAble2d
import com.gitee.wsl.mathematics.number.compareTo
import kotlin.math.PI

interface EllipseShape2d<N:Number,V: Coordinate2<N, V>,S: SizeAble2d<N, S>>: EllipseShape<N, V, S>, CloseShape2d<N, V>,PointShape2d<N,V>{

    val xRadius get() = radius.width
    val yRadius get() = radius.height

    override val area:N  get() = (PI * radius.width * radius.height)
    override val perimeter:N get() {
        if (radius.width == radius.height) return (PI * 2.0 * radius.width) // Circle formula
        val (a, b) = radius
        val h = ((a - b) * (a - b)) / ((a + b) * (a + b))
        return (PI * (a + b) * (1 + ((3 * h) / (10 + sqrt(4 - (3 * h))))))
    }

    override val closed: Boolean get() = true

    fun containsY(y: N): Boolean = abs(center.y - y) < radius.height
    fun containsX(x: N): Boolean = abs(center.x - x) < radius.width

    override fun distance(p: V): N {
        val p = p - center
        val scaledPoint = createPoint2(p.x / radius.width, p.y / radius.height)
        val length = scaledPoint.length
        return (length - 1) * min(radius.width, radius.height)
    }

    override fun containsPoint(p: Coordinate2<N, *>): Boolean {
        if (radius.isEmpty()) return false
        // Check if the point is inside the ellipse using the ellipse equation:
        // (x - centerX)^2 / radiusX^2 + (y - centerY)^2 / radiusY^2 <= 1
        return (sqr(p.x - center.x) / sqr(radius.width)) + (sqr(p.y - center.y) / sqr(radius.height)) <= 1
    }

    override fun normalVectorAt(p: V): V {
        val pointOnEllipse = p - center
        val (a, b) = radius
        val normal = createPoint2(pointOnEllipse.x / (a * a), pointOnEllipse.y / (b * b))
        return normal.normalized
        //val d = p - center
        //val r2 = radius.toVector() * radius.toVector()
        //return (d / r2).normalized
    }


}